﻿using System;
using System.Security.Cryptography;

namespace PhiStore.Util
{
    /// <summary>
    /// This class generates cryptographically safe random values
    /// Note: This approach is not really for HPC
    /// </summary>
    public static class RandomGenerator
    {
        private static RNGCryptoServiceProvider rand = new RNGCryptoServiceProvider();

        /// <summary>
        /// Generates a random Long
        /// </summary>
        public static long Long
        {
            get
            {
                long result = 0L;
                lock (rand)
                {
                    byte[] bytes = new byte[8];
                    rand.GetBytes(bytes);
                    result = BitConverter.ToInt64(bytes, 0);
                }
                return result;
            }
        }

        /// <summary>
        /// Generates a random Unsigned Long
        /// </summary>
        public static ulong ULong
        {
            get
            {
                ulong result = 0L;
                lock (rand)
                {
                    byte[] bytes = new byte[8];
                    rand.GetBytes(bytes);
                    result = BitConverter.ToUInt64(bytes, 0);
                }
                return result;
            }
        }

        /// <summary>
        /// Generates a random Int
        /// </summary>
        public static int Int
        {
            get
            {
                int result = 0;
                lock (rand)
                {
                    byte[] bytes = new byte[4];
                    rand.GetBytes(bytes);
                    result = BitConverter.ToInt32(bytes, 0);
                }
                return result;
            }
        }

        /// <summary>
        /// Generates a random integer
        /// </summary>
        /// <param name="Max">Max value (not included)</param>
        /// <returns>a random integer</returns>
        public static int Integer(int Max)
        {
            int random = RandomGenerator.Int;
            random = random < 0 ? random * -1 : random; 
            return random % Max;
        }

        /// <summary>
        /// Generates a random integer
        /// </summary>
        /// <param name="Min">Min value (included)</param>
        /// <param name="Max">Max value (not included)</param>
        /// <returns>a random integer</returns>
        public static int Integer(int Min, int Max)
        {
            return Min + Integer(Max - Min);
        }


        /// <summary>
        /// Generates a random Byte
        /// </summary>
        public static byte Byte
        {
            get
            {
                byte result = new byte();
                lock (rand)
                {
                    byte[] bytes = new byte[1];
                    rand.GetBytes(bytes);
                    result = bytes[0];
                }
                return result;
            }
        }

        /// <summary>
        /// Generates an array of random Byte
        /// </summary>
        /// <param name="length">length of array</param>
        /// <returns>an array of random bytes</returns>
        public static byte[] Bytes(int length)
        {
            byte[] result = new byte[length];
            lock (rand)
            {
                rand.GetBytes(result);
            }
            return result;
        }
    }
}
